import calendar
import locale

from aiogram import types, Router
from aiogram.utils.keyboard import InlineKeyboardBuilder

from database import models
from tg_bot.keyboards.callback_factory import ActionCall, AdminActionCall, BackCall, AdminMenuCall, SeatCall, \
    CategoryCall, ProductCall, ConsumableCall, SaleCall, TeamCall, CopySaleCall, DateCall, PayCall
from tg_bot.keyboards.paginator import MyPaginator

CHANGE_NAME = 'Изменить название'

locale.setlocale(locale.LC_ALL, 'ru_RU.UTF-8')


async def concatenate_key(*keyboards: types.InlineKeyboardMarkup | InlineKeyboardBuilder) -> types.InlineKeyboardMarkup:
    """
    Конкатенация инлайн клавиатур.

    :param keyboards: Инлайн клавиатуры.
    :return: Объединение инлайн клавиатур.
    """
    keyboard = InlineKeyboardBuilder()
    for key in keyboards:
        if isinstance(key, types.InlineKeyboardMarkup):
            keyboard.attach(InlineKeyboardBuilder.from_markup(key))
        elif isinstance(key, InlineKeyboardBuilder):
            keyboard.attach(key)
    return keyboard.as_markup()


async def pagination(page: int, pages: int) -> types.InlineKeyboardMarkup:
    """
    Кнопки пагинации назад и вперед, если список позволяет.

    :param page: Текущая страница.
    :param pages: Кол-во страниц.
    :return: Инлайн клавиатура пагинации.
    """
    key = InlineKeyboardBuilder()
    if page == 1 and pages > 1:
        key.button(
            text='⏩',
            callback_data=AdminActionCall(action='next_page')
        )
    elif page > 1 and page != pages:
        key.button(
            text='⏪',
            callback_data=AdminActionCall(action='prev_page')
        )
        key.button(
            text='⏩',
            callback_data=AdminActionCall(action='next_page')
        )
    elif page != 1 and page == pages:
        key.button(
            text='⏪',
            callback_data=AdminActionCall(action='prev_page')
        )
    return key.as_markup()


async def get_pages_count(total_count: int, lines_page: int = 8) -> int:
    """
    Получаем список страниц по-общему кол-ву и кол-ву строк на странице.

    :param total_count: Общее кол-во элементов.
    :param lines_page: Кол-во элементов на странице.
    :return: Кол-во страниц.
    """
    pages = total_count // lines_page
    pages += 1 if total_count % lines_page > 0 else 0
    return pages


async def get_start_stop_slice(page: int = 1, lines_page: int = 8) -> tuple[int, int]:
    """
    Получаем начало и конец среда по текущей странице и кол-ву элементов на ней.

    :param page: Текущая страница.
    :param lines_page: Кол-во элементов на странице.
    :return: Начало и конец среза.
    """
    start_slice = (page - 1) * lines_page
    end_slice = page * lines_page
    return start_slice, end_slice


async def cancel() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура отмены действия.

    :return: Инлайн клавиатура.
    """
    key = InlineKeyboardBuilder()
    key.button(text='❌ Отмена', callback_data=ActionCall(action='cancel'))
    return key.as_markup()


async def back(to: str = 'admin_menu') -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура 'назад'.

    :param to: Строка колбека.
    :return: Инлайн клавиатура.
    """
    key = InlineKeyboardBuilder()
    key.button(text='⬅️ Назад', callback_data=BackCall(to=to))
    return key.as_markup()


async def find_keyboard(help_text: str, text_to_search: str) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура для поиска в инлайн режиме.

    ----

    :param help_text: Вспомогательный текст
    :param text_to_search: Ключевая фраза поиска.
    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text=f'Поиск - {help_text}',
               switch_inline_query_current_chat=f'FIND {text_to_search.upper()} ')
    key.adjust(1)
    return key.as_markup()


async def confirm() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='✓ Подтвердить', callback_data=ActionCall(action='confirm'))
    return key.as_markup()


async def delete_key() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='🗑️ Удалить', callback_data=ActionCall(action='delete'))
    return key.as_markup()


async def pass_key() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='Пропустить', callback_data=ActionCall(action='pass'))
    return key.as_markup()


async def confirm_or_cancel() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура подтверждения и/или отмены.

    :return: Инлайн клавиатура.
    """
    key = InlineKeyboardBuilder()
    key.button(text='✓ Подтвердить', callback_data=ActionCall(action='confirm'))
    key.button(text='❌ Отменить', callback_data=ActionCall(action='cancel'))
    return key.as_markup()


async def sales_choice() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура с текстом <Выбрать продажи>

    :return: Inline Keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Выбрать продажи',
               callback_data=AdminActionCall(action='sales_choice'))
    key.adjust(1)
    return key.as_markup()


async def choice_all():
    key = InlineKeyboardBuilder()
    key.button(text='Выбрать все', callback_data=AdminActionCall(action='choose_all'))
    key.adjust(1)
    return key.as_markup()


async def admin_menu() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура главного меню админа.

    :return: Инлайн клавиатура.
    """
    key = InlineKeyboardBuilder()
    key.button(text='🛠Конфиг бота', callback_data=AdminMenuCall(item='config'))
    key.button(text='🪑Посадки', callback_data=AdminMenuCall(item='seat'))
    key.button(text='📚Категории', callback_data=AdminMenuCall(item='category'))
    key.button(text='🍸Расходники', callback_data=AdminMenuCall(item='consumable'))
    key.button(text='Работа со столами', callback_data=AdminMenuCall(item='work_seat'))
    key.button(text='Статистика', callback_data=AdminMenuCall(item='statistics'))
    key.button(text='Админы', callback_data=AdminMenuCall(item='admins'))
    key.adjust(1)
    return key.as_markup()


async def admin_settings_menu() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура настроек админа.

    ----
    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Бонус за приглашение',
               callback_data=AdminActionCall(action='change_invite_bonus'))
    key.button(text='Бонус за рефералов',
               callback_data=AdminActionCall(action='change_ref_bonus'))
    key.button(text='Лимит предупреждений',
               callback_data=AdminActionCall(action='change_warns_count'))
    key.adjust(1)
    return key.as_markup()


async def add_seat() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура добавления посадки.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='➕ Добавить стол', callback_data=AdminActionCall(action='add_seat'))
    return key.as_markup()


class SeatPaginator(MyPaginator):
    def _build_pagination_keyboard(self) -> types.InlineKeyboardMarkup:
        builder = InlineKeyboardBuilder()
        seats = models.Seat.objects.all().order_by('pk')
        self.set_max_page_and_update_current_page(seats.count())
        start_slice, end_slice = self.get_start_stop_slice()
        for seat in seats[start_slice:end_slice]:
            builder.button(
                text=f'{seat.name}',
                callback_data=SeatCall(pk=seat.pk))
        builder.adjust(1)
        self._add_pagination_buttons(builder)
        return builder.as_markup()


async def seat_settings(back_to: str = None) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура настроек для посадки.

    ----

    :param back_to: Callback кнопки назад.
    :return: Inline Keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text=CHANGE_NAME,
               callback_data=AdminActionCall(action='change_seat_name'))
    key.button(text='Изменить вместимость',
               callback_data=AdminActionCall(action='change_seat_max'))
    key.button(text='Изменить фото',
               callback_data=AdminActionCall(action='change_seat_photo'))
    key.button(text='Удалить',
               callback_data=AdminActionCall(action='delete_seat'))
    key.adjust(1)
    key = key.as_markup()
    if back_to:
        key = await concatenate_key(key, await back(back_to))
    return key


async def add_category() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура:
        - Добавить категорию
    ----

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='➕ Добавить категорию', callback_data=AdminActionCall(action='add_category'))
    return key.as_markup()


class CategoryPaginator(MyPaginator):
    def __init__(self,
                 router: Router,
                 current_page: int = 1,
                 for_users: bool = False,
                 before_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
                 after_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
                 lines_on_page: int = 8):
        self.for_users = for_users
        super().__init__(
            router,
            current_page,
            before_pagination_keyboards,
            after_pagination_keyboards,
            lines_on_page
        )

    def _build_pagination_keyboard(self) -> types.InlineKeyboardMarkup:
        builder = InlineKeyboardBuilder()
        category_list = models.Category.objects.filter(is_active=True).order_by('pk')
        if self.for_users:
            category_list = category_list.filter(is_visible=True)
        self.set_max_page_and_update_current_page(category_list.count())
        start_slice, end_slice = self.get_start_stop_slice()
        for category in category_list[start_slice:end_slice]:
            builder.button(
                text=f'{category.name}',
                callback_data=CategoryCall(pk=category.pk))
        builder.adjust(1)
        self._add_pagination_buttons(builder)
        return builder.as_markup()


async def category_settings() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура настроек категории.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Изменить...', callback_data=AdminActionCall(action='None'))
    key.button(text='🔧Название',
               callback_data=AdminActionCall(action='change_category_name'))
    key.button(text='Описание🔧',
               callback_data=AdminActionCall(action='change_category_desc'))
    key.button(text='🔧Отображение🔧',
               callback_data=AdminActionCall(action='change_category_display'))
    key.adjust(1, 2, 1)
    return key.as_markup()


async def add_product() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура:
        - Добавить продукт
    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='➕ Добавить продукт', callback_data=AdminActionCall(action='add_product'))
    return key.as_markup()


class ProductPaginator(MyPaginator):
    def __init__(
            self,
            router: Router,
            category: models.Category | None = None,
            for_users: bool = False,
            current_page: int = 1,
            before_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
            after_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
            lines_on_page: int = 8
    ):
        self.for_users = for_users
        self.category = category
        super().__init__(
            router,
            current_page,
            before_pagination_keyboards,
            after_pagination_keyboards,
            lines_on_page
        )

    def _build_pagination_keyboard(self) -> types.InlineKeyboardMarkup:
        builder = InlineKeyboardBuilder()
        if self.category:
            products_list = self.category.products.filter(is_active=True)
        else:
            products_list = models.Product.objects.all().order_by('pk')
        if self.for_users:
            products_list = products_list.filter(is_visible=True)
        self.set_max_page_and_update_current_page(products_list.count())
        start_slice, end_slice = self.get_start_stop_slice()
        for product in products_list[start_slice:end_slice]:
            builder.button(
                text=f'{product.name}',
                callback_data=ProductCall(pk=product.pk))
        builder.adjust(1)
        self._add_pagination_buttons(builder)
        return builder.as_markup()


async def product_settings(back_to: str = None) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура для настройки продукта.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='➕ Добавить расходники', callback_data=AdminActionCall(action='change_product_compound'))
    key.button(text='Изменить технологичку', callback_data=AdminActionCall(action='change_product_help'))
    key.button(text=CHANGE_NAME, callback_data=AdminActionCall(action='change_product_name'))
    key.button(text='Изменить описание', callback_data=AdminActionCall(action='change_product_desc'))
    key.button(text='Изменить цену', callback_data=AdminActionCall(action='change_product_price'))
    key.button(text='Изменить фото', callback_data=AdminActionCall(action='change_product_photo'))
    key.button(text='Изменить отображение', callback_data=AdminActionCall(action='change_product_display'))
    key.adjust(1)
    key = key.as_markup()
    if back_to:
        key = await concatenate_key(key, await back(back_to))
    return key


async def add_consumable() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура 'Добавить расходник'.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='➕ Добавить расходник', callback_data=AdminActionCall(action='add_consumable'))
    return key.as_markup()


class ConsumablePaginator(MyPaginator):
    def _build_pagination_keyboard(self) -> types.InlineKeyboardMarkup:
        builder = InlineKeyboardBuilder()
        consumable_list = models.Consumable.objects.all().order_by('pk')
        self.set_max_page_and_update_current_page(consumable_list.count())
        start_slice, end_slice = self.get_start_stop_slice()
        for consumable in consumable_list[start_slice:end_slice]:
            builder.button(
                text=f'{consumable.name} | {consumable.total}{consumable.unit}',
                callback_data=ConsumableCall(pk=consumable.pk))
        builder.adjust(1)
        self._add_pagination_buttons(builder)
        return builder.as_markup()


# async def consumable_pagination(page: int = 1, lines_page: int = 8) -> types.InlineKeyboardMarkup:
#     """
#     Инлайн клавиатура из списка расходников и пагинации.
#
#     :param page: Индекс текущей страницы.
#     :param lines_page: Кол-во элементов на странице.
#     :return: Inline keyboard.
#     """
#     start_slice, end_slice = await get_start_stop_slice(page, lines_page)
#     consumable_list = models.Consumable.objects.all().order_by('pk')
#     key = InlineKeyboardBuilder()
#     for consumable in consumable_list[start_slice:end_slice]:
#         key.button(text=f'{consumable.name} | {consumable.total}{consumable.unit}',
#                    callback_data=ConsumableCall(pk=consumable.pk))
#     pages = await get_pages_count(consumable_list.count(), lines_page)
#     pagination_key = await pagination(page, pages)
#     key.adjust(1)
#     return await concatenate_key(key.as_markup(), pagination_key)


# async def consumable_menu(page: int = 1, lines_page: int = 8, back_to: str = None) -> types.InlineKeyboardMarkup:
#     """
#     Инлайн клавиатура следующего вида:
#         - Добавить расходник
#         - `<Список расходников>`
#         - `<Пагинация расходников>`
#         - Кнопка назад, если указан callback.
#     ----
#
#     :param page: Индекс текущей страницы.
#     :param lines_page: Кол-во элементов на странице.
#     :param back_to: Callback для кнопки назад.
#     :return: Inline keyboard.
#     """
#     key = await concatenate_key(await add_consumable(), await consumable_pagination(page, lines_page))
#     if back_to:
#         key = await concatenate_key(key, await back(back_to))
#     return key


async def consumable_settings(back_to: str = None) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура настроек расходников.

    :param back_to: Callback для кнопки назад.
    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text=CHANGE_NAME, callback_data=AdminActionCall(action='change_consumable_name'))
    key.button(text='Изменить цену', callback_data=AdminActionCall(action='change_consumable_price'))
    key.button(text='Изменить меру измерения',
               callback_data=AdminActionCall(action='change_consumable_unit'))
    key.button(text='Изменить общее кол-во',
               callback_data=AdminActionCall(action='change_consumable_total'))
    key.adjust(1)
    key = key.as_markup()
    if back_to:
        key = await concatenate_key(key, await back(back_to))
    return key


async def free_seat() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура свободных столов.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    free_tables = models.Seat.get_free()
    if free_tables.count() > 0:
        key.button(text='🟢Свободные столы🟢', callback_data='None')
        for table in free_tables:
            key.button(text=table.name, callback_data=SeatCall(pk=table.pk))
    key.adjust(1)
    return key.as_markup()


async def busy_seat() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура занятых столов.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    busy_tables = models.Seat.get_busy()
    if busy_tables.count() > 0:
        key.button(text='🔴Занятые столы🔴', callback_data='None')
        for table in busy_tables:
            key.button(text=table.name, callback_data=SeatCall(pk=table.pk))
    key.adjust(1)
    return key.as_markup()


async def joined_seat(seat: models.Seat) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура объединенных столов.

    :param seat: ORM-модель посадки.
    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    joined_tables = models.Seat.objects.filter(
        join=seat
    ).order_by('pk')
    if joined_tables.count() > 0:
        key.button(text='🚫Объединенные столы🚫', callback_data='None')
        for table in joined_tables:
            key.button(text=table.name, callback_data=SeatCall(pk=table.pk))
    key.adjust(1)
    return key.as_markup()


async def free_and_busy_seat(back_to: str = None) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура следующего типа:
        - 🟢Свободные столы🟢
        - `<Список свободных столов>`
        - 🔴Занятые столы🔴
        - `<Список занятых столов>`
        - Кнопка назад, если указан callback
    ----

    :param back_to: Callback для кнопки назад.
    :return: Inline keyboard.
    """
    key = await concatenate_key(await free_seat(),
                                await busy_seat())
    if back_to:
        key = await concatenate_key(key, await back(back_to))
    return key


async def open_seat() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура "Посадить гостей".

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Посадить гостей', callback_data=AdminActionCall(action='open_seat'))
    return key.as_markup()


async def close_seat() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура "Закрыть стол".

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Закрыть стол', callback_data=AdminActionCall(action='close_seat'))
    return key.as_markup()


async def add_sale() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура "Добавить заказ".

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='➕ Добавить заказ', callback_data=AdminActionCall(action='add_sale'))
    return key.as_markup()


class SalesPaginator(MyPaginator):
    def __init__(
            self,
            router: Router,
            sales_main: models.SalesMain,
            with_copy_sale: bool = False,
            current_page: int =1,
            before_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
            after_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
            lines_on_page: int = 8
    ):
        self.sales_main: models.SalesMain = sales_main
        self.with_copy_sale = with_copy_sale
        super().__init__(
            router,
            current_page,
            before_pagination_keyboards,
            after_pagination_keyboards,
            lines_on_page
        )

    def _build_pagination_keyboard(self) -> types.InlineKeyboardMarkup:
        builder = InlineKeyboardBuilder()
        sales = self.sales_main.sales.values('product').annotate(count=models.models.Count('product')).order_by('count')
        self.set_max_page_and_update_current_page(sales.count())
        start_slice, end_slice = self.get_start_stop_slice()
        for sale in sales[start_slice:end_slice]:
            product = models.Product.objects.filter(pk=sale['product']).first()
            emoji = '🔴' if self.sales_main.get_rest_sum_by_product(product) > 0 else '🟢'
            builder.button(
                text=f'{emoji} {sale["count"]}-шт {product.name}',
                callback_data=ProductCall(pk=product.pk))
            if self.with_copy_sale:
                builder.button(text='➕', callback_data=CopySaleCall(pk=product.pk))
        builder.adjust(2 if self.with_copy_sale else 1)
        self._add_pagination_buttons(builder)
        return builder.as_markup()


async def sales_pagination_with_copy(sales_main: models.SalesMain,
                                     page: int = 1,
                                     lines_page: int = 8) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура с продажами и пагинацией.

    :param sales_main: ORM-модель главных продаж.
    :param page: Индекс текущей страницы.
    :param lines_page: Кол-во элементов на странице.
    :return: Inline keyboard.
    """
    start_slice, end_slice = await get_start_stop_slice(page, lines_page)
    sales = sales_main.sales.values('product').annotate(count=models.models.Count('product')).order_by('count')
    key = InlineKeyboardBuilder()
    for sale in sales[start_slice:end_slice]:
        product = models.Product.objects.filter(pk=sale['product']).first()
        emoji = '🔴' if sales_main.get_rest_sum_by_product(product) > 0 else '🟢'
        # key.button(text=f'{emoji} {sale.product.name}', callback_data=SaleCall(pk=sale.pk))
        key.button(text=f'{emoji} {sale["count"]}-шт {product.name}',
                   callback_data=ProductCall(pk=product.pk))
        key.button(text='➕', callback_data=CopySaleCall(pk=product.pk))
    pages = await get_pages_count(sales.count(), lines_page)
    pagination_key = await pagination(page, pages)
    key.adjust(2)
    return await concatenate_key(key.as_markup(), pagination_key)


async def busy_seat_options() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура типа:
        - Объединить
        - Пересадить

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Объединить', callback_data=AdminActionCall(action='join_seat'))
    key.button(text='Пересадить', callback_data=AdminActionCall(action='move_seat'))
    key.adjust(2)
    return key.as_markup()


async def pay_method_choice() -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура со способом оплаты.

    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Нал', callback_data=AdminActionCall(action='cash'))
    key.button(text='БН', callback_data=AdminActionCall(action='sber'))
    key.button(text='Терминал', callback_data=AdminActionCall(action='terminal'))
    return key.as_markup()


async def pay_sum_keyboard(amount: int | float) -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text=f'Оплатить {amount}', callback_data=PayCall(amount=amount))
    key.adjust(1)
    return key.as_markup()


async def seat_sales_choice_or_close(sales_main: models.SalesMain) -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder().as_markup()
    if sales_main.sales.all().count() > 0:
        key = await concatenate_key(key, await sales_choice())
    if sales_main.get_rest_sum() == 0:
        key = await concatenate_key(key, await close_seat())
    return key


async def busy_seat_menu(sales_main: models.SalesMain,
                         page: int = 1,
                         lines_page: int = 8,
                         back_to: str = None) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура следующего типа:
        - Добавить заказ
        - `<Список проданных товаров> <Дублировать заказ>`
        - `<Пагинация проданных товаров>`
        - Скидка, объединить, пересадить
        - Close seat or Pay sales.
        - Кнопка назад, если указан callback
    ----

    :param sales_main: ORM-модель главных продаж.
    :param page: индекс текущей страницы.
    :param lines_page: Кол-во элементов на странице.
    :param back_to: Callback для кнопки назад.
    :return: Inline keyboard.
    """
    key = await concatenate_key(
        await add_sale(),
        await sales_pagination_with_copy(sales_main, page, lines_page),
        await busy_seat_options()
    )
    if sales_main.sales.all().count() > 0:
        key = await concatenate_key(key, await sales_choice())
    if sales_main.get_rest_sum() == 0:
        key = await concatenate_key(key, await close_seat())
    if back_to:
        key = await concatenate_key(key, await back(back_to))
    return key


async def team_choice(back_to: str = None) -> types.InlineKeyboardMarkup:
    """
    Инлайн клавиатура со списком команды и кнопкой назад.

    :param back_to: Callback для кнопки назад.
    :return: Inline keyboard.
    """
    key = InlineKeyboardBuilder()
    for member in models.Team.objects.filter(is_active=True).order_by('pk'):
        key.button(text=f'{member.name}', callback_data=TeamCall(pk=member.pk))
    key.adjust(1)
    key = key.as_markup()
    if back_to:
        key = await concatenate_key(key, await back(back_to))
    return key


async def set_discount() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='Указать скидку',
               callback_data=AdminActionCall(action='set_discount'))
    return key.as_markup()


class SaleProductsPaginator(MyPaginator):
    def __init__(
            self,
            router: Router,
            sales_main: models.SalesMain,
            product: models.Product = None,
            checkout_mode: bool = False,
            sales_id: list[int] = None,
            current_page: int = 1,
            before_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
            after_pagination_keyboards: list[types.InlineKeyboardMarkup] = None,
            lines_page: int = 8
    ):
        self.sales_main: models.SalesMain = sales_main
        self.product: models.Product | None = product
        self.checkout_mode: bool = checkout_mode
        self.sales_id: list[int] = sales_id if sales_id else []
        super().__init__(
            router,
            current_page,
            before_pagination_keyboards,
            after_pagination_keyboards,
            lines_page
        )

    def _build_pagination_keyboard(self) -> types.InlineKeyboardMarkup:
        builder = InlineKeyboardBuilder()
        sales = self.sales_main.sales.all()
        if self.product:
            sales = sales.filter(product=self.product)
        self.set_max_page_and_update_current_page(sales.count())
        start_slice, end_slice = self.get_start_stop_slice()
        checkout_emoji = ''
        for sale in sales[start_slice:end_slice]:
            if self.checkout_mode:
                checkout_emoji = '●' if sale.pk in self.sales_id else '○'
            pay_emoji = '🔴' if sale.get_rest_sum() > 0 else '🟢'
            builder.button(
                text=f'{checkout_emoji} {pay_emoji}{sale.product.name}',
                callback_data=SaleCall(pk=sale.pk))
            user_text = sale.user.name if sale.user else 'не указано...'
            builder.button(text=f'({sale.team.name}) {user_text}', callback_data='None')
        builder.adjust(2)
        self._add_pagination_buttons(builder)
        return builder.as_markup()


# async def sale_products_pagination(
#         sales_main: models.SalesMain,
#         product: models.Product | None = None,
#         page: int = 1,
#         checkout_mode: bool = False,
#         sales_id: list[int] = None,
#         lines_page: int = 8,
# ) -> types.InlineKeyboardMarkup:
#     """
#     Инлайн клавиатура одинаковых товаров из sales main.
#
#     :param sales_main: ORM-модель главных продаж.
#     :param product: ORM-модель продукта.
#     :param page: Индекс текущей страницы.
#     :param checkout_mode: Добавлять ли checkout emoji.
#     :param sales_id: PK-ключи выбранных продаж.
#     :param lines_page: Кол-во элементов на странице.
#     :return: Inline keyboard.
#     """
#     if sales_id is None:
#         sales_id = []
#     start_slice, end_slice = await get_start_stop_slice(page, lines_page)
#     sales = sales_main.sales.all()
#     if product:
#         sales = sales.filter(product=product)
#     key = InlineKeyboardBuilder()
#     checkout_emoji = ''
#     for sale in sales[start_slice:end_slice]:
#         if checkout_mode:
#             checkout_emoji = '●' if sale.pk in sales_id else '○'
#         pay_emoji = '🔴' if sale.get_rest_sum() > 0 else '🟢'
#         key.button(text=f'{checkout_emoji} {pay_emoji}{sale.product.name}',
#                    callback_data=SaleCall(pk=sale.pk))
#         user_text = sale.user.name if sale.user else 'не указано...'
#         key.button(text=f'({sale.team.name}) {user_text}', callback_data='None')
#     pages = await get_pages_count(sales.count(), lines_page)
#     pagination_key = await pagination(page, pages)
#     key.adjust(2)
#     return await concatenate_key(key.as_markup(), pagination_key)

async def sales_actions(back_to: str = 'seat_choice') -> types.InlineKeyboardMarkup:
    key = await concatenate_key(
        await find_keyboard('Пользователи', 'user'),
        await set_discount(),
        await pay_method_choice(),
        await delete_key(),
        await back(back_to)
    )
    return key


async def statistics_choice() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='За смену', callback_data=AdminActionCall(action='day_stat'))
    key.button(text='За период', callback_data=AdminActionCall(action='stat_by_period'))
    return key.as_markup()


async def referral_program() -> types.InlineKeyboardMarkup:
    """
    Клавиатура с кнопкой <Реферальная программа>.

    ----
    :return: InlineKeyboardMarkup.
    """
    key = InlineKeyboardBuilder()
    key.button(text='Реферальная программа',
               callback_data=ActionCall(action='referral_program'))
    key.adjust(1)
    return key.as_markup()


async def balance_history() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='История баланса',
               callback_data=ActionCall(action='balance_history'))
    key.adjust(1)
    return key.as_markup()


async def voucher_keyboard() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='Активация ваучеров',
               callback_data=ActionCall(action='voucher_activation'))
    key.adjust(1)
    return key.as_markup()


async def calendar_keyboard(year: int, month: int) -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='<<<', callback_data=ActionCall(action='prev_year'))
    key.button(text=f'{year}', callback_data='None')
    key.button(text='>>>', callback_data=ActionCall(action='next_year'))
    key.button(text='<<', callback_data=ActionCall(action='prev_month'))
    key.button(text=f'{calendar.month_name[month]}', callback_data='None')
    key.button(text='>>', callback_data=ActionCall(action='next_month'))
    for i in calendar.day_abbr:
        key.button(text=i, callback_data='None')
    month_calendar = calendar.monthcalendar(year, month)
    for week in month_calendar:
        for day in week:
            if day == 0:
                key.button(text=' ', callback_data='None')
            else:
                key.button(text=f'{day}', callback_data=DateCall(year=year, month=month, day=day))
    key.adjust(3, 3, 7)
    return key.as_markup()


async def today_stat() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='За смену',
               callback_data=AdminActionCall(action='today_stat'))
    key.adjust(1)
    return key.as_markup()


async def order_keyboard() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(text='Заказать',
               callback_data=ActionCall(action='order_product'))
    key.adjust(1)
    return key.as_markup()


async def menu_keyboard() -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(
        text='Меню',
        callback_data=ActionCall(action='menu')
    )
    key.adjust(1)
    return key.as_markup()


async def counter(current_value: int = 1) -> types.InlineKeyboardMarkup:
    key = InlineKeyboardBuilder()
    key.button(
        text='➖',
        callback_data=ActionCall(action='minus_value')
    )
    key.button(
        text=f'{current_value}',
        callback_data='None'
    )
    key.button(
        text='➕',
        callback_data=ActionCall(action='plus_value')
    )
    key.adjust(3)
    return key.as_markup()
